<?php
/**
 * PortalApplication class file
 *
 * @author Steen Rabol <steen.rabol@gmail.com>
 * @link http://www.pradoportal.dk/
 * @copyright Copyright &copy; 2006,2007,2008 Steen Rabol
 * @license http://www.pradoportal.dk
 * @version $Id: PortalApplication.php 467 2011-01-25 17:24:30Z steen.rabol $
 * @package Pradoportal.Common
 */

Prado::using('System.TApplication');
Prado::using('System.Data.TDbConnection');
Prado::using('System.Web.TUrlMapping');

/**
 *
 * @package Pradoportal.Common
 */
class PortalApplication extends TApplication
{
	private	$_layoutareas		= null;
	private $_portalBasePath	= "";
	private $_portalbaseurl		= "";
	private $_portalrelurl		= "/";

	private $_dbconn			= null;
	private $_onlineinfo		= array();

	private $_langstrings		= array();
	private	$_langkey			= 'APPLICATION';
	private	$_culture			= null;
	private	$_upgrademode		= false;

	private $_appl_lang_loaded	= false;


	private static $_application	= null;

	private $_licinfo				= null; //array();

	public function getLicensType()
	{
		if(is_null($this->_licinfo))
			$this->_licinfo = PortalUtil::LicensInformation();
		
		return $this->_licinfo['LICTYPE'];
	}

	public function getUpgradeMode()
	{
		return $this->_upgrademode;
	}

	public function getCulture()
	{
		if($this->_culture === null)
		{
			$this->_culture	= (isset($this->Parameters['DefaultLanguage']) ? $this->Parameters['DefaultLanguage'] : 'en');
		}

		return $this->_culture;
	}

	public function setCulture($p_value)
	{
		$this->_culture	= $p_value;
	}

	public function getLanguageKey()
	{
		return $this->_langkey;
	}

	public function getLanguageStrings()
	{
		return $this->_langstrings;
	}

	public function setLanguageStrings($p_value = array())
	{
		$this->_langstrings	= $p_value;
	}

	public function loadLanguageStrings($p_lkey	= 'APPLICATION')
	{
		$trecords	= false;

		if($this->Parameters['RunMode'] == "Install")
		{
			return;
		}

		if($p_lkey == 'APPLICATION' && $this->_appl_lang_loaded == true)
		{
			return;
		}

		$culture	= $this->Culture;

		if(strpos($culture ,'_',0) !== false)
		{
			$culture	= substr($culture,0,strpos($culture,'_',0));
		}

		// culture specific cache file
		$cacheFile	= $this->RuntimePath . DIRECTORY_SEPARATOR . $culture . ".lang.cache";

		if(!file_exists($cacheFile))
		{
			try
			{
				$sql 		= "select fromvalue,tovalue from tbllangstrings where culture='$culture' and lkey='$p_lkey'";
				$dr			= $this->DbConnection->createCommand($sql)->query();
				foreach($dr as $record)
				{
					$this->_langstrings[$record['fromvalue']] = $record['tovalue'];
				}
				file_put_contents($cacheFile,Prado::serialize($this->_langstrings),LOCK_EX);
			}
			catch(Exception $e) {}
		}
		else
		{
			$this->_langstrings = Prado::unserialize(file_get_contents($cacheFile));
		}

		if($p_lkey == 'APPLICATION')
		{
			$this->_appl_lang_loaded = true;
		}
	}

	public function Translate($p_str, $parameters=array())
	{
		$params	= array();
        $t_str	= "";

		foreach($parameters as $key => $value)
		{
			$params['{'.$key.'}'] = $value;
		}

		if(isset($this->_langstrings[$p_str]) && strlen($this->_langstrings[$p_str]))
		{
			$t_str = strtr($this->_langstrings[$p_str], $params);
		}
		else
		{
			// Auto create ??
			if(isset($this->Parameters['autocreatelangstrings']) && TPropertyValue::ensureBoolean($this->Parameters['autocreatelangstrings']) == true)
			{
				PortalUtil::CreateLangString($p_str);
				return $p_str;
			}
			else if(isset($this->Parameters['notranslation']) && TPropertyValue::ensureBoolean($this->Parameters['notranslation']) == true)
			{
				return $p_str;
			}
			else
			{
				$t_str = "@@" . $p_str . "@@";
			}
		}

		return $t_str;
	}

	public static function setApplication($application)
	{
		if(self::$_application	!==	null)
		{
			throw new TInvalidOperationException('prado_application_singleton_required');
		}

		self::$_application=$application;
	}

	public static function getApplication()
	{
		return self::$_application;
	}

	public function __construct($basePath='protected',$cacheConfig=true)
	{
		// Copy of TApplication constructor
		parent::__construct($basePath,$cacheConfig);
		PortalApplication::setApplication($this);
		// Check required PHP version
		$minphpversion	= "5.2.0";
		if(version_compare(phpversion(),$minphpversion,"<") == 1)
		{
			PortalUtil::fatalError("This version of Prado Portal requires PHP version $minphpversion or higher.<br>Your version is " . phpversion());
		}

		$pradoVersion 		= Prado::getVersion();
		$minpradoversion	= "3.1.6";

		if(version_compare($pradoVersion,$minpradoversion,"<"))
		{
			$this->fatalError("This version of Prado Portal requires PRADO version $minpradoversion.<br>Your version is $pradoVersion.");
		}

		$this->CheckSettingsFile();
	}

	public function getLayoutAreas()
	{
		return $this->_layoutareas;
	}

	public function setLayoutAreas($value)
	{
		if($this->_layoutareas === null)
		{
			$this->_layoutareas	= array();
		}

		if(is_array($value))
		{
			foreach($value as $v)
			{
				$this->_layoutareas[] = $v;
			}
		}
		else if(is_string($value))
		{
			$this->_layoutareas[] = array("id" => $value, "name" => $value);
		}
	}

	protected function validateParameters()
	{
		if(!isset($this->Parameters['GridPageSize']))
		{
			$this->Parameters['GridPageSize'] = 20;
		}
	}

	/**
	 *
	 */
	protected function initApplication()
	{
		PortalBM::start("Prado.initApplication");
		parent::initApplication();
		PortalBM::stop("Prado.initApplication");
		$this->validateParameters();
		PortalBM::start("Portal.initApplication");

			
		if($this->Service instanceof PortalPageService) // TPageService
		{
			$this->BuildUrlMappingsForPath();

			$logger = $this->getModule('log');
			if($this->Parameters['RunMode'] != "Install")
			{
				if(!isset($this->Parameters['ValidationKey']) || empty($this->Parameters['ValidationKey']))
					$this->Parameters['ValidationKey'] = 'stofferloffer';

				if(!isset($this->Parameters['OpenIdPassword']) || empty($this->Parameters['OpenIdPassword']))
					$this->Parameters['OpenIdPassword'] = 'stofferloffer';

				$this->SecurityManager->ValidationKey = $this->Parameters['ValidationKey'];

				// Set the authorization

				if(TPropertyValue::ensureBoolean($this->Parameters['AuthMode']) !== false)
				{
					$am = $this->getModule('auth');
					$am->Default = TPropertyValue::ensureBoolean($this->Parameters['AuthMode']);
				}

				// Set the application mode
				if(!isset($this->Parameters['AppMode']))
				{
					$this->Parameters['AppMode'] = 2;
				}

				switch($this->Parameters['AppMode'])
				{
					case 0: $this->Mode	= TApplicationMode::Off; break;
					case 1: $this->Mode	= TApplicationMode::Debug; break;
					case 2: $this->Mode	= TApplicationMode::Normal; break;
					case 3: $this->Mode	= TApplicationMode::Performance; break;
				}

				$logger = $this->getModule('log');
				// To help the user...
				$this->Parameters['autocreatelangstrings'] = true;

				if($this->Mode == TApplicationMode::Debug)
				{
					$this->Parameters['autocreatelangstrings'] = false;
					error_reporting(E_ALL);
					// Add the browser log route
					if($logger !== null)
					{
						$browserlog = Prado::createComponent('TBrowserLogRoute');
						if($browserlog !== null)
						{
							$browserlog->Levels		= "Info,DEBUG, INFO, NOTICE, WARNING, ERROR, ALERT, FATAL";
							$browserlog->Categories	= "Info,Debug,Uncategorized";
							$logger->addRoute($browserlog);
						}
						else
						{
							PortalUtil::fatalError("Faild to create log component");
						}
					}
					else
					{
						PortalUtil::fatalError("Faild to create log component");
					}
				}

				$this->UpgradeCheck();

				if($logger !== null)
				{
					$dblog = Prado::createComponent('Application.Common.PortalDbLogRoute');
					$dblog->Levels	= "Error,Alert,Fatal";
					try
					{
						$logger->addRoute($dblog);
					}
					catch(Exception $e)
					{
						PortalUtil::fatalError($e->getMessage());
					}
				}

				$this->InstallDirCheck();
			}
			else
			{
				// In installation mode we enable a file based logger
				if($logger !== null)
				{
					$filelog = Prado::createComponent('TFileLogRoute');
					if($filelog !== null)
					{
						$filelog->Levels		= "Info,DEBUG, INFO, NOTICE, WARNING, ERROR, ALERT, FATAL";
						$filelog->Categories	= "Info,Debug,Uncategorized";
						$logger->addRoute($filelog);
					}
				}
			}
		}
		//$this->_licinfo = PortalUtil::LicensInformation();
		PortalBM::stop("Portal.initApplication");
	}

	public function onPreRunService()
	{
		parent::onPreRunService();
		if($this->Service instanceof PortalPageService) // TPageService
		{
			if(TPropertyValue::ensureBoolean($this->Parameters['TrackOnlineUsers']))
			{
				$this->TrackOnlineUsers();
			}

			if(TPropertyValue::ensureBoolean($this->Parameters['TrackUserActivity']))
			{
				$this->TrackUserActivity();
			}
		}
	}

	public function TrackOnlineUsers()
	{
		Prado::using('Application.Common.Data.PortalUserOnlineRecord');
		PortalUtil::getIP();
		$ip				= $_SERVER['REMOTE_ADDR'];
		
		if(empty($ip))
		{
			return;
		}

		$sessionid		= session_id();
		$timestamp		= time();
		$timeout		= 180; // If there is no activity in 3 minutes
		$difftime		= $timestamp - $timeout;
		$userid			= $this->User->Id;
		$conn			= $this->DbConnection;
		$conn->Active	= true;

		// Clear 'old' values
		$sql = "delete from tbluseronline where timestamp+$timeout < $timestamp";
		$conn->createCommand($sql)->execute();

		$excludeips = (isset($this->Parameters['trackexclip']) ? explode(",",$this->Parameters['trackexclip']) : array());
		if(!in_array($ip,$excludeips))	// Don't track local trafic... in_array
		{
			$ou	= $conn->createCommand("select * from tbluseronline where sessionid='$sessionid'")->queryRow();

			if($ou !== false)
			{
				$page = $this->Service->RequestedPagePath;
				$sql = "update tbluseronline set timestamp='$timestamp', userid='$userid', page='$page' where id='" . $ou['id'] . "'";
				$conn->createCommand($sql)->execute();
			}
			else
			{
				$rec 			= new PortalUserOnlineRecord();
				$rec->ip		= $ip;
				$rec->sessionid	= $sessionid;
				$rec->timestamp	= $timestamp;
				$rec->userid	= $this->User->Id;
				$rec->page		= $this->Service->RequestedPagePath;
				$rec->save();
			}
		}
	}

	public function TrackUserActivity()
	{
		$domain	= "";
        $url	= "";

		if(substr($this->Service->RequestedPagePath,0,5) == "Admin")
		{
			return;
		}

		include_once(Prado::getPathOfNamespace('Application.Common.3rdParty.shortstat') . '/shortstat.php');
		$ip		= $_SERVER['REMOTE_ADDR'];
		$cntry	= SI_determineCountry($ip);
		$lang	= SI_determineLanguage();
		$ref	= isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : "";

		if(!empty($ref))
		{
			$url 	= parse_url($ref);
			$domain	= str_replace("www.","",$url['host']);
		}
		else
		{
			$url	= "";
			$domain	= "";
		}

		$res	= PortalUtil::request_uri();
		$ua		= $_SERVER['HTTP_USER_AGENT'];
		$br		= SI_parseUserAgent($ua);
		$dt		= time();

		if($url != "")
		{
			SI_sniffKeywords($url);
		}

		$query = "INSERT INTO tblshortstat (remote_ip,country,language,domain,referer,resource,user_agent,platform,browser,version,dt)
				  VALUES ('$ip','$cntry','$lang','$domain','$ref','$res','$ua','$br[platform]','$br[browser]','$br[version]',$dt)";

		$this->DbConnection->createCommand($query)->Execute();
	}

	public function getOnlineInfo()
	{
		$conn			= $this->DbConnection;
		$guestsonline	= $conn->createCommand("select count(id) as guests from tbluseronline where userid=0")->queryScalar();
		$usersonline	= $conn->createCommand("select count(id) as users from tbluseronline where userid!=0")->queryScalar();
		return array($guestsonline,$usersonline);
	}

	public function getDbConnection()
    {
		if($this->_dbconn === null)
		{
			$this->_dbconn = new TDbConnection(strtolower($this->Parameters['DbType']) . ':host=' . $this->Parameters['DbHost'] . ';dbname=' . $this->Parameters['DbDatabase'] , $this->Parameters['DbUser'],$this->Parameters['DbPassword']);
			if(!$this->_dbconn->Active)
			{
				$this->_dbconn->Active = true;
			}
		}

        return $this->_dbconn;
    }

	public function getDataAccess()
	{
		return $this->DbConnection;
	}

	private function InstallDirCheck()
	{
		// Check if the Installation dir still exists
		if(file_exists($this->PortalBasePath ."/protected/Pages/Install"))
		{
			if(!TPropertyValue::ensureBoolean($this->Parameters['IgnoreInstallDir'])) // This is an UNDOCUMENTED feature, don't depend on it!!
			{
				if(($this->Service->RequestedPagePath != "System.ErrorReport") && ($this->Service->RequestedPagePath != "Install.Install"))
				{
					PortalUtil::fatalError("Installation directory exists<br>You have to delete it before you can use Prado Portal",false);
				}
			}
		}
	}

	public function getPortalBasePath()
	{
		return $this->_portalBasePath;
	}

	public function setPortalBasePath($value)
	{
		$this->_portalBasePath	= TPropertyValue::ensureString($value);
	}

	public function getPortalBaseUrl()
	{
		return $this->_portalbaseurl;
	}

	public function setPortalBaseUrl($value)
	{
		$this->_portalbaseurl	= TPropertyValue::ensureString($value);
	}

	public function getPortalRelUrl()
	{
		return $this->_portalrelurl;
	}

	public function setPortalRelUrl($value)
	{
		$this->_portalrelurl	= $value;
	}

	private function CheckSettingsFile()
	{
		$settingsfile	= $this->BasePath.'/Data/Settings.xml';
		if(!file_exists($settingsfile))
		{
			// Applicetion is not 'installed' so we create a default settings file which allow us to start the installation script
			$dom			= new TXmlDocument;
			$dom->Encoding	= 'utf-8';
			$dom->TagName	= 'parameters';
			$elements	= $dom->Elements;
			$elements[]	= $this->createParameter('SiteTitle',"Prado Portal");
			$elements[] = $this->createParameter('SiteSubTitle',"A Prado-driven portal");
			$elements[]	= $this->createParameter('SiteOwner',"");
			$elements[]	= $this->createParameter('AdminEmail',"");
			$elements[]	= $this->createParameter('MultipleUser',"true");
			$elements[]	= $this->createParameter('AccountApproval',"false");
			$elements[]	= $this->createParameter('ThemeName',"Default");
			$elements[]	= $this->createParameter('AdminThemeName',"Default");
			$elements[]	= $this->createParameter('AdminRole',"3");
			$elements[]	= $this->createParameter('MinRole',"1");
			$elements[]	= $this->createParameter('NewUserRole',"2");
			$elements[]	= $this->createParameter('PortalLayout','PortalLayout');
			$elements[]	= $this->createParameter('PortalAdminLayout','AdminLayout');
			$elements[]	= $this->createParameter('DbType','MySQL');
			$elements[]	= $this->createParameter('DbHost',"localhost");
			$elements[]	= $this->createParameter('DbDatabase',"");
			$elements[]	= $this->createParameter('DbUser',"");
			$elements[]	= $this->createParameter('DbPassword',"");
			$elements[]	= $this->createParameter('UseCookieExpire',"true");
			$elements[]	= $this->createParameter('CookiePrefix',"pradoportal");
			$elements[]	= $this->createParameter('LoginExpire',"30");
			$elements[]	= $this->createParameter('RunMode',"Install");
			$elements[]	= $this->createParameter('DefaultLanguage',"en");
			$elements[]	= $this->createParameter('AuthMode',"1");
			$elements[] = $this->createParameter('ValidationKey', 'this_is_the_default_validation_key');
			$elements[] = $this->createParameter('IgnoreInstallDir','1');
			$elements[] = $this->createParameter('TrackOnlineUsers','false');
			$elements[] = $this->createParameter('TrackUserActivity','false');
			$elements[] = $this->createParameter('AppMode','2');
			$elements[] = $this->createParameter('NewAccountAction','0');
			$elements[] = $this->createParameter('PortalVersion',$this->PortalVersion());
			$elements[] = $this->createParameter('GridPageSize','20');
			$elements[] = $this->createParameter('FriendlyUrl','false');

			$dom->saveToFile($settingsfile);

			$this->Parameters['RunMode'] = "Install";
		}
	}

	protected function createParameter($id,$value)
	{
		$element	= new TXmlElement('parameter');
		$element->Attributes['id']=$id;
		$element->Attributes['value']=TPropertyValue::ensureString($value);
		return $element;
	}

	public function PortalVersion()
	{
		return '1.2.1';
	}

	public function PortalName()
	{
		return 'Prado Portal';
	}

	public function DeleteConfigCache()
	{
		$cachefile = $this->RuntimePath . DIRECTORY_SEPARATOR . self::CONFIGCACHE_FILE;
		@unlink($cachefile);
	}

	public function DeleteLanguageCache()
	{
		Prado::using('Application.Common.Data.PortalLanguageRecord');
		$actLang	= PortalLanguageRecord::finder()->findAll("active =?",1);

		if($actLang !== 0 && is_array($actLang) && count($actLang) > 0)
		{
			foreach($actLang as $aLang)
			{
				$cachefile = $this->RuntimePath . DIRECTORY_SEPARATOR . $aLang->culture . ".lang.cache";

				if(file_exists($cachefile))
				{
					try
					{
						unlink($cachefile);
					}
					catch (Exception $e)
					{
						PortalUtil::Log($e->getCode() . ' ' . $e->getMessage());
					}
				}
			}
		}
	}

	public function getNeedUpgrade()
	{
		return false;
	}

	public function UpgradeCheck()
	{
		if($this->Parameters['RunMode'] == 'Install')
		{
			return;
		}

        $db 	= $this->DbConnection;
		$sql 	= "select * from tblconfig where name='portalversion'";
		$verrow	= $db->createCommand($sql)->queryRow();
        
		if(!isset($this->Parameters['PortalVersion']))
		{
            $this->Parameters['Portalversion'] = $this->PortalVersion();
        }

		if(!$verrow)
		{
			$sql	= "insert into tblconfig(name,value,culture) values('portalversion','{$this->PortalVersion()}','en')";
			$db->createCommand($sql)->execute();
            $this->UpgradeCheck();
		}

        $vercheck       = version_compare(TPropertyValue::ensureString($verrow['value']),TPropertyValue::ensureString($this->PortalVersion()));
        if($vercheck !== 0)
		{
			$this->_upgrademode = true;
			Prado::using('Application.Common.Upgrade.PortalUpgrade');
			$upgrade	= new PortalUpgrade($this,$verrow['id'],$verrow['value']);
			$upgrade->Upgrade();
			$this->_upgrademode = false;
			// Delete the install dir
			//$installdir = Prado::getPathOfNamespace('Application.Pages.Install');
			//$this->DeleteInstallDir($installdir);
		}
	}

	private function DeleteInstallDir($dir)
	{
		if(!file_exists($dir))
			return;

		$current_dir = @opendir($dir);
		while($entryname = readdir($current_dir))
		{
			if(is_dir("$dir/$entryname") and ($entryname != "." and $entryname!=".."))
			{
				$this->DeleteInstallDir("${dir}/${entryname}",true);
			}
			elseif($entryname != "." and $entryname!="..")
			{
				@unlink("${dir}/${entryname}");
			}
		}

		@closedir($current_dir);
		@rmdir($dir);
	}

	public function fatalError($msg)
	{
		PortalUtil::fatalError($msg);
	}

	public function BuildUrlMappingsForPath($force = false)
	{
		if(!TPropertyValue::ensureBoolean($this->Parameters['FriendlyUrl']))
		{
			return;
		}
		$filename	= Prado::getPathOfNamespace('Application.runtime') . '/' . 'urlmap.xml';

		if(!$force && file_exists($filename))
		{
			return;
		}

		$dom			= new TXmlDocument;
		$dom->Encoding	= 'utf-8';
		$dom->TagName	= 'urls';
		$elements		= $dom->Elements;

		$paths = PortalPagePathRecord::finder()->findAll();
		if($paths)
		{
			foreach($paths as $path)
			{
				$elements[]	= $this->CreateUrlMapping($path->path . '.*',$path->path .'/{*}');
			}
		}

		// Allways our own...
		$elements[]	= $this->CreateUrlMapping('System.*','System/{*}');
		$elements[]	= $this->CreateUrlMapping('Admin.*','Admin/{*}');
		$elements[]	= $this->CreateUrlMapping('Common.*','Common/{*}');
		$elements[]	= $this->CreateUrlMapping('*');

		$dom->saveToFile($filename);
	}

	protected function CreateUrlMapping($p,$pp = null,$ppp = null)
	{
		$element	= new TXmlElement('url');
		$element->Attributes['ServiceId']	= 'page';
		$element->Attributes['ServiceParameter']	= $p;
		
		if(!is_null($pp))
		{
			$element->Attributes['pattern']	= $pp;
		}
		else
		{
			$element->Attributes['pattern']	= "{". $p . "}";
		}
		$element->Attributes['UrlFormat']	= 'Path';
		$element->Attributes['UrlParamSeparator']	= '/';

		return $element;
	}

	public function run()
	{
		PortalBM::start('Portal.run');
		parent::run();
		PortalBM::stop('Portal.run');

		if($this->Application->Mode	== TApplicationMode::Debug)
		{
			PortalBM::ViewAllBmResults();
		}
	}

	public function getApplicationCss()
	{
		$applcss = array();
		$applcss['.grid-header']		= "";
		$applcss['.grid-row1']			= "";
		$applcss['.grid-row2']			= "";
		$applcss['.grid']				= "";
		$applcss['.grid-row-selected']	= "";
		$applcss['.grid-row-edit']		= "";
		$applcss['.grid-pager']			= "";
		$applcss['.input-error1']		= "";
		$applcss['.input-error2']		= "";
		$applcss['.input-error3']		= "";

		$applcss['.tab-panel']			= array('position' => 'relative', 'float'=> 'left', 'width' => '100%');
		$applcss['.tab-normal']			= "";
		$applcss['.tab-active']			= "";
		$applcss['.tab-active a']		= "";
		$applcss['.tab-normal a']		= "";

		$applcss['.tab-view']			= "";
		$applcss['.tab-normal a:hover, .a:focus']	= "";
		$applcss['.portalerror']			= "";
		$applcss['.portlet']				= "";

		$applcss['.tinymce_editor_body']	= array(
												'background' => '#ffffff',
												'background-color' => '#ffffff',
												'color' => '#000000',
												'text-align' => 'left'
												);

		return $applcss;
	}
}

?>